package com.cloud.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.cloud.common.constants.HeaderConstant;
import com.cloud.common.constants.RedisCacheKeys;
import com.cloud.common.redis.RedisStringCacheSupport;
import com.cloud.common.response.SimpleResponse;
import com.cloud.common.syse.HttpCodeE;
import com.cloud.common.syse.SysRespStatusE;
import com.cloud.common.utils.TokenUtil;
import com.cloud.common.utils.ValidationUtils;
import com.cloud.gateway.config.PathPropertyConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.function.Consumer;

@Slf4j
@Component
public class AuthenticationFilter implements GlobalFilter, Ordered {


    @Autowired
    private PathPropertyConfig propertyConfig;

//    private static final String START_TIME = "startTime";
//
//    private static final Long logTime = 1000L;

    @Autowired
    private RedisStringCacheSupport cacheStr;


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        List<String> skipAuthUrls = propertyConfig.getIgnoredTokenPath();
        //获取请求  响应
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse originalResponse = exchange.getResponse();
        // 获取请求头
        HttpHeaders headers = request.getHeaders();
        //获取url
        String url = request.getURI().getPath();
        //跳过不需要验证的路径
        if (null != skipAuthUrls && skipAuthUrls.contains(url)) {
            //放行
            return chain.filter(exchange);
        }
        String authorization=headers.getFirst(HeaderConstant.AUTHORIZATION);
        if (StringUtils.isEmpty(authorization)) {
            DataBuffer buffer = this.getReturnBuffer(originalResponse,"Authorization为空");
            return originalResponse.writeWith(Flux.just(buffer));
        }
        if(!TokenUtil.verifyToken(authorization)){
            DataBuffer buffer = this.getReturnBuffer(originalResponse,"登陆过期请重新登录");
            return originalResponse.writeWith(Flux.just(buffer));
        }
        //验证token是否失效或者更新-----后台管理
        String adminUserId=TokenUtil.getField(authorization, HeaderConstant.ADMINUSERID);
        if(!StringUtils.isEmpty(adminUserId)){
            String cachedAuthorization = cacheStr.getCached(RedisCacheKeys.USER_ADMIN_TOKEN_KEY + adminUserId);
            if(StringUtils.isEmpty(cachedAuthorization)){
                DataBuffer buffer = this.getReturnBuffer(originalResponse,"登陆过期请重新登录");
                return originalResponse.writeWith(Flux.just(buffer));
            }
            if(!authorization.equals(cachedAuthorization)){
                DataBuffer buffer = this.getReturnBuffer(originalResponse,"登陆失效请重新登录");
                return originalResponse.writeWith(Flux.just(buffer));
            }
        }

        String adminUsername=TokenUtil.getField(authorization, HeaderConstant.ADMINUSERNAME);
        String adminUserStatus=TokenUtil.getField(authorization, HeaderConstant.ADMINUSERSTATUS);
        //验证token是否失效或者更新-----app用户
        String appUserId=TokenUtil.getField(authorization, HeaderConstant.APPUSERID);
        if(!StringUtils.isEmpty(appUserId)){
            String cachedAuthorization = cacheStr.getCached(RedisCacheKeys.USER_APP_TOKEN_KEY + appUserId);
            if(StringUtils.isEmpty(cachedAuthorization)){
                DataBuffer buffer = this.getReturnBuffer(originalResponse,"登陆过期请重新登录");
                return originalResponse.writeWith(Flux.just(buffer));
            }
            if(!authorization.equals(cachedAuthorization)){
                DataBuffer buffer = this.getReturnBuffer(originalResponse,"登陆失效请重新登录");
                return originalResponse.writeWith(Flux.just(buffer));
            }
        }

        String appUsername=TokenUtil.getField(authorization, HeaderConstant.APPUSERNAME);
        String appUserStatus=TokenUtil.getField(authorization, HeaderConstant.APPUSERSTATUS);
        Consumer<HttpHeaders> httpHeaders = httpHeader -> {
            //后台管理用户信息
            if(!StringUtils.isEmpty(adminUserId))httpHeader.set(HeaderConstant.ADMINUSERID, adminUserId);
            if(!StringUtils.isEmpty(adminUsername))httpHeader.set(HeaderConstant.ADMINUSERNAME, adminUsername);
            if(!StringUtils.isEmpty(adminUserStatus))httpHeader.set(HeaderConstant.ADMINUSERSTATUS, adminUserStatus);
            //app用户信息
            if(!StringUtils.isEmpty(appUserId))httpHeader.set(HeaderConstant.APPUSERID, appUserId);
            if(!StringUtils.isEmpty(appUsername))httpHeader.set(HeaderConstant.APPUSERNAME, appUsername);
            if(!StringUtils.isEmpty(appUserStatus))httpHeader.set(HeaderConstant.APPUSERSTATUS, appUserStatus);
        };
        request.mutate().headers(httpHeaders).build();
        exchange.mutate().request(request).build();
        //放行
        return chain.filter(exchange);
//        exchange.getAttributes().put(START_TIME, System.currentTimeMillis());
//        return chain.filter(exchange).then( Mono.fromRunnable(() -> {
//            Long startTime = exchange.getAttribute(START_TIME);
//            if (startTime != null) {
//                Long executeTime = (System.currentTimeMillis() - startTime);
//                if(executeTime > logTime){
//                    String info = String.format("Method:{%s} Host:{%s} Path:{%s} Query:{%s}",
//                            request.getMethod().name(),
//                            request.getURI().getHost(),
//                            request.getURI().getPath(),
//                            request.getQueryParams());
//                    log.warn(info);
//                    log.warn(exchange.getRequest().getURI().getRawPath() + " : " + executeTime + "ms");
//                }
//            }
//        }));
    }

    @Override
    public int getOrder() {
        return 1;
    }


    /**
     * 返回给前端json相关数据方法
     * @param originalResponse
     * @return
     */
    private DataBuffer getReturnBuffer(ServerHttpResponse originalResponse,String message) {
        originalResponse.setStatusCode(HttpStatus.OK);
        originalResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        SimpleResponse resp=new SimpleResponse();
        resp.setReturnErrMsg(resp, HttpCodeE.参数有误.value, SysRespStatusE.失败.getDesc(), message);
        DataBuffer buffer = originalResponse.bufferFactory().wrap(JSON.toJSONString(resp).getBytes());
        return buffer;
    }
}
